package com.googlecode.connectlet.crypto.cipher.mode;

import com.googlecode.connectlet.crypto.cipher.Decipheror;
import com.googlecode.connectlet.util.Bytes;

public class CbcPkcs5PaddingDecipheror extends CbcNoPaddingDecipheror {
	private byte[] padding;
	private boolean bof;
	private Pkcs5PaddingDecipherorFinal finalBlock;

	public CbcPkcs5PaddingDecipheror(Decipheror cipher) {
		super(cipher);
		padding = new byte[blockSize];
		finalBlock = new Pkcs5PaddingDecipherorFinal(padding);
	}

	public CbcPkcs5PaddingDecipheror(Decipheror cipher, byte[] iv) {
		this(cipher);
		init(iv);
	}

	@Override
	public void init(byte[] iv) {
		super.init(iv);
		bof = true;
	}

	@Override
	protected int decryptFirst(byte[] output, int outputOffset) {
		if (bof) {
			cipher.decrypt(block, 0, padding, 0);
			Bytes.xor(chain, 0, padding, 0, blockSize);
			System.arraycopy(block, 0, chain, 0, blockSize);
			bof = false;
			return 0;
		}
		decryptNext(output, outputOffset);
		return blockSize;
	}

	@Override
	protected void decryptNext(byte[] output, int outputOffset) {
		System.arraycopy(padding, 0, output, outputOffset, blockSize);
		cipher.decrypt(block, 0, padding, 0);
		Bytes.xor(chain, 0, padding, 0, blockSize);
		System.arraycopy(block, 0, chain, 0, blockSize);
	}

	@Override
	public int doFinal(byte[] output, int outputOffset) {
		return finalBlock.doFinal(output, outputOffset);
	}
}